Technical Note TN2007
The CGDirectDisplay API

目次

このテクニカルノートでは、Mac OS X で使用される CGDirectDisplay API のリファレンス情報を示します。

CGDirectDisplay API は、ディスプレイモード、カーソル位置、ガンマテーブル、およびその他のローレベル機能への直接的なアクセスを提供するように設計されています。この API は、従来の DrawSprocket、Display Manager、およびその他類似の API を、統合化された単一の API に置き換えて拡張することを目的としています。

このテクニカルノートでは、重要なデータ型、2 つの典型的な使用パターン、およびこの API に含まれるすべての関数呼び出しについて説明します。なお、「Technical Note 2008」では、CGDirectPalette によって提供される API を取り扱っています。

更新日: 2000 年 11 月 8 日






定義

 

CGDirectDisplay API で使用されるデータ型

Data Type

データ型

CGDirectDisplayID

ディスプレイへの opaque 参照 (kCGDirectMainDisplay は便宜上メインディスプレイを参照します)

CGDirectPaletteRef

パレットへの opaque 参照

CGDisplayCount

符号なし 32 ビット値

CGTableCount

符号なし 32 ビット値

CGDisplayCoord

ディスプレイ上の座標を表す符号付き 32 ビット値 (座標の原点はディスプレイの左上隅)

CGByteValue

ガンマ/パレット関数によって使用される符号なし 8 ビット値

CGOpenGLDisplayMask

OpenGL ディスプレイマスクビットを保持する符号なし 32 ビット値 (それぞれのビットは異なるディスプレイを表します)

CGBeamPosition

ディスプレイ上のリフレッシュビームの位置を表す符号なし 32 ビット値 (0 はディスプレイの上端)

CGMouseDelta

マウス位置に加えられた変更を表す符号付き 32 ビット値

CGDisplayErr

符号付き 32 ビットエラー値

ページの先頭に戻る

 

典型的な使い方

 

単純な使用パターン

単純なケースでは、まずメインディスプレイを取得し、そのディスプレイに必要とする色数と解像度に最も近いモードを設定します。この後は、ディスプレイのベースアドレスに対して直接的に、必要とする任意の描画を実行することができます。描画が終了したら、ディスプレイモードを元に戻して、ディスプレイをリリースします。

CFDictionaryRef mode;
CFDictionaryRef originalMode;
size_t desiredBitDepth = 16;
size_t desiredWidth = 1024;
size_t desiredHeight = 768;
boolean_t exactMatch;
    
originalMode = CGDisplayCurrentMode( kCGDirectMainDisplay );
    
mode = CGDisplayBestModeForParameters(
    kCGDirectMainDisplay,
    desiredBitDepth, desiredWidth,
    desiredHeight, &exactMatch );
                        
if ( NULL != mode ) {
        /* 厳密な一致が必要な場合は、
        ここで exactMatch をチェックする */
         
    CGDisplayCapture( kCGDirectMainDisplay );
    CGDisplaySwitchToMode( kCGDirectMainDisplay, mode );
    CGDisplayHideCursor( kCGDirectMainDisplay );
        
        /* ここで描画/ゲームループを実行する。
        CGDisplayBaseAddress() を使用して、
        ディスプレイのベースアドレスを取得する */
       
    CGDisplayShowCursor( kCGDirectMainDisplay );
    CGDisplaySwitchToMode( kCGDirectMainDisplay, originalMode );
    CGDisplayRelease( kCGDirectMainDisplay );
}
                  

リスト1 単純なケースのコードリスティング

 

複雑な使用パターン

複雑なケースでは、使用するディスプレイをより詳細に制御したり、「最適なモード」が何を意味するかを自分自身で決定する必要があります。このケースでは、アクティブディスプレイの配列を取得し、そのリストを対象にそれぞれのディスプレイがサポートするモードを繰り返し検査して、アプリケーションに最適なディスプレイ/モードの組み合わせを選択します。

CFDictionaryRef originalMode;
CGDirectDisplayID displays[kMaxDisplays];
CGDisplayCount numDisplays;
CGDisplayCount i;
CGDisplayErr err;
CFDictionaryRef bestMode = NULL;
CGDirectDisplayID bestDisplay = kCGDirectMainDisplay;
                  
err = CGGetActiveDisplayList(
    kMaxDisplays,
    displays,
    &numDisplays);
if ( err != kCGDisplayNoErr )
{
    printf("Cannot get displays (%d)¥n", err);
    exit( 1 );
}
                  
for ( i = 0; i < numDisplays; i++ )
{
    CFDictionaryRef mode;
    CFIndex i, cnt;
    CGDirectDisplayID dspy;
    CFArrayRef modeList;
    
    dspy = displays[i];
                  
    modeList = CGDisplayAvailableModes(dspy);
    if ( NULL != modeList )
    {
        //  それぞれのモードを調べる
        cnt = CFArrayGetCount( modeList );
        
        for ( i = 0; i < cnt; i++ )
        {
            //  Pull the mode dictionary out of the CFArray
            mode = CFArrayGetValueAtIndex( modeList, i );
            
            /* ここでモードを検査する。
            thisModeIsTheBest( mode ) は、それぞれのモードを評価する
            ユーザ定義関数で、最適のモード (戻り値) を選択する */
            if ( thisModeIsTheBest( mode ) )
            if ( thisModeIsTheBest( mode ) )
            {
                bestMode = mode;
                bestDisplay = dspy;
            }
        }
    }
}
                  
//  この時点で、最適のモードと
//  それに対応するディスプレイ ID を識別した
if ( NULL != bestMode )
{
    originalMode = CGDisplayCurrentMode( bestDisplay );
                  
    CGDisplayCapture( bestDisplay );
    CGDisplaySwitchToMode( bestDisplay, bestMode );
    CGDisplayHideCursor( bestDisplay );
    
    //  ここで描画/ゲームループを実行する。
    //  CGDisplayBaseAddress() を使用して、ディスプレイのベースアドレスを取得する
   
    CGDisplayShowCursor( bestDisplay );
    CGDisplaySwitchToMode( bestDisplay, originalMode );
    CGDisplayRelease( bestDisplay );
    }
                

リスト 2 複雑なケースのコードリスティング

ページの先頭に戻る

 

ディスプレイ ID の検出

CGDisplayErr CGGetActiveDisplayList(
    CGDisplayCount maxDisplays,
    CGDirectDisplayID * activeDspys,
    CGDisplayCount * dspyCnt);
  • アクティブディスプレイをすべてリストします。
CGDisplayErr CGGetDisplaysWithPoint(
    CGPoint point,
    CGDisplayCount maxDisplays,
    CGDirectDisplayID * dspys,
    CGDisplayCount * dspyCnt);
  • point を含むすべてのディスプレイをリストします。
  • どのディスプレイも point を含んでいない場合は、dspyCnt に 0 を返します。
  • なお、複数のディスプレイが重複する場合があるため (たとえば、ミラーリングなどにより)、dspys に複数のディスプレイ ID が含まれることもあります。
CGDisplayErr CGGetDisplaysWithRect(
    CGRect rect,
    CGDisplayCount maxDisplays,
    CGDirectDisplayID * dspys,
    CGDisplayCount * dspyCnt);
  • rect の少なくとも一部を含むすべてのディスプレイをリストします。
  • どのディスプレイも rect を含んでいない場合は dspyCnt に 0 を返します。
  • なお、複数のディスプレイが重複する場合があるため (たとえば、ミラーリングなどにより)、dspys に複数のディスプレイ ID が含まれることもあります。

ページの先頭に戻る

 

ディスプレイモードの選択

CFDictionaryRef CGDisplayCurrentMode(
    CGDirectDisplayID display);
  • 現在のディスプレイモードを記述する CFDictionaryRef を返します。
  • 無効なディスプレイ ID には NULL を返します。
CFArrayRef CGDisplayAvailableModes(
    CGDirectDisplayID display);
  • すべての使用可能なモードを記述する CFDictionary の CFArray を返します。
  • 無効なディスプレイ ID には NULL を返します。
CFDictionaryRef CGDisplayBestModeForParameters(
    CGDirectDisplayID display,
    size_t bitsPerPixel,
    size_t width, 
    size_t height, 
    boolean_t *exactMatch);
  • 指定以上の次元で、指定された色数のディスプレイモードを検出します。
  • 厳密に一致する色数が検出されない場合は、指定以上の次元で、次に大きな色数をチェックします。
  • 条件を満たすモードがない場合は、現在のモードを返します。
  • 厳密に一致する色数が検出された場合は exactMatch (NULL でない場合) に true を設定し、厳密に一致する色数が使用可能でない場合は exactMatch に false を設定します。
  • 無効なディスプレイ ID には NULL を返します。

ページの先頭に戻る

 

ディスプレイモード情報の取得

CGRect CGDisplayBounds(CGDirectDisplayID display);
  • スクリーンサイトとグローバル座標での原点を返します。
  • 無効なディスプレイ ID に対応する空の矩形を返します。
size_t CGDisplayPixelsWide(
    CGDirectDisplayID display);
  • ディスプレイの幅をピクセル単位で返します。
  • 無効なディスプレイ ID には 0 を返します。D.
size_t CGDisplayPixelsHigh(
    CGDirectDisplayID display);
  • ディスプレイの高さをピクセル単位で返します。
  • 無効なディスプレイ ID には 0 を返します。
size_t CGDisplayBitsPerPixel(
    CGDirectDisplayID display);
  • 指定されたディスプレイの現在の色数を返します。
  • 無効なディスプレイ ID には 0 を返します。
size_t CGDisplayBitsPerSample(
    CGDirectDisplayID display);
  • 指定されたディスプレイのカラーサンプル当たりのビット数を返します。
  • 無効なディスプレイ ID には 0 を返します。
size_t CGDisplaySamplesPerPixel(
    CGDirectDisplayID display);
  • 指定されたディスプレイのカラーサンプル当たりのビット数を返します。
  • 無効なディスプレイ ID には 0 を返します。
size_t CGDisplayBytesPerRow(
    CGDirectDisplayID display);
  • 指定されたディスプレイの行当たりのバイト数を返します。
  • 無効なディスプレイ ID には 0 を返します。
void * CGDisplayBaseAddress(
    CGDirectDisplayID display);
  • 指定されたディスプレイのベースアドレスを返します。
  • 無効なディスプレイ ID には NULL を返します。
  • なお、ディスプレイがキャプチャされなかった場合は、返されたアドレスが読み取り専用メモリを参照していることもあります
void * CGDisplayAddressForPosition(
    CGDirectDisplayID display, 
    CGDisplayCoord x, 
    CGDisplayCoord y);
  • スクリーン座標内の位置 (X,Y) に対応するアドレスを返します。
  • (0,0) はディスプレイの左上隅を表します。
  • ディスプレイ ID が無効な場合、または X 座標と Y 座標が境界を超えている場合は NULL を返します。
  • なお、ディスプレイがキャプチャされなかった場合は、返されたアドレスが読み取り専用メモリを参照していることもあります。

ページの先頭に戻る

 

CGDirectDisplayID と OpenGL の使い方

CGDisplayErr CGGetDisplaysWithOpenGLDisplayMask(
    CGOpenGLDisplayMask mask,
    CGDisplayCount maxDisplays,
    CGDirectDisplayID * dspys,
    CGDisplayCount * dspyCnt);
  • マスク内で指定されたマスクビットを持つディスプレイのリストを検出します。
  • なお、マスク内で複数のディスプレイが指定される場合があるため、dspys 配列に複数のディスプレイ ID が含まれることもあります。
CGOpenGLDisplayMask CGDisplayIDToOpenGLDisplayMask(
    CGDirectDisplayID display);
  • 指定されたディスプレイ ID に対応する OpenGL ディスプレイマスクを検出します。
  • 無効なディスプレイ ID には 0 を返します。

ページの先頭に戻る

 

ディスプレイのキャプチャとリリース

CGDisplayErr CGDisplayCapture(
    CGDirectDisplayID display);
  • 指定されたディスプレイをキャプチャしてシールドウインドウをセットし、同期的なモードの変更を可能にします。
CGDisplayErr CGDisplayRelease(
    CGDirectDisplayID display);
  • 指定されたディスプレイをリリースし、シールドウインドウを削除します。
boolean_t CGDisplayIsCaptured(
    CGDirectDisplayID display);
  • 指定されたディスプレイがキャプチャされている場合は true を返します。

ページの先頭に戻る

 

ディスプレイモードの切り替え

CGDisplayErr CGDisplaySwitchToMode(
    CGDirectDisplayID display,
    CFDictionaryRef mode);
  • 指定されたディスプレイをモード辞書に記述されているモードに切り替えます。
  • なお、モードの切り替えにより、ディスプレイのパラメータとアドレスが変更される場合があります。
  • 選択されたディスプレイモードは、プログラムが実行されているかぎり保持されます。プログラムの実行が中止されると、ディスプレイモードは、「システム環境設定」の「モニタ」パネルで設定されているモードに自動的に戻ります。
  • なお、ディスプレイモードの切り替えは、キャプチャされたディスプレイに適用されるときのみ同期的に実行されます。ディスプレイがキャプチャされていない場合、モードの切り替えは非同期的に実行され、CGDisplaySwitchToMode が値を返すときに完了しないこともあります。

ページの先頭に戻る

 

ディスプレイガンマおよびパレットの調整

CGDisplayErr CGSetDisplayTransferByFormula(
    CGDirectDisplayID display,
    CGGammaValue redMin,
    CGGammaValue redMax,
    CGGammaValue redGamma,
    CGGammaValue greenMin,
    CGGammaValue greenMax,
    CGGammaValue greenGamma,
    CGGammaValue blueMin,
    CGGammaValue blueMax,
    CGGammaValue blueGamma);
  • それぞれのチャネルに対応する最小値、最大値、およびガンマを指定する式からディスプレイガンマ/転送関数を設定します。
  • ガンマ値は 0.0 よりも大きくなければなりません。
  • (1.0 / 1.6) という値を指定して、1.6 のアンチガンマを取得します。
  • 最小値は 0.0 以上で、1.0 未満でなければなりません。
  • 最大値は 0.0 よりも大きく、1.0 以下でなければなりません。
  • いずれかの値が範囲を超えているか、最大値が最小値以上である場合は kCGSRangeCheck エラーを返します。
  • 値は、0 から 1 までのインデックスの範囲にわたって関数をサンプリングすることで計算されます。value = Min + ((Max - Min) * pow(index, Gamma))
  • 計算結果の値はマシン固有の形式に変換され、ハードウェアにロードされます。
CGDisplayErr CGGetDisplayTransferByFormula(
    CGDirectDisplayID display,
    CGGammaValue *redMin,
    CGGammaValue *redMax,
    CGGammaValue *redGamma,
    CGGammaValue *greenMin,
    CGGammaValue *greenMax,
    CGGammaValue *greenGamma,
    CGGammaValue *blueMin,
    CGGammaValue *blueMax,
    CGGammaValue *blueGamma);
  • それぞれのチャネルに対応する最小値、最大値、およびガンマを指定する式からディスプレイガンマ/転送関数を取得します。
CGDisplayErr CGSetDisplayTransferByTable(
    CGDirectDisplayID display,
    CGTableCount tableSize,
    const CGGammaValue  *redTable,
    const CGGammaValue  *greenTable,
    const CGGammaValue  *blueTable);
  • それぞれのチャネルに対応するデータのテーブルを使用して、ディスプレイガンマ/転送関数を設定します。
  • それぞれのテーブル内の値は、0.0 から 1.0 の範囲の値を含んでいなければなりません。
  • 赤、緑、および青チャネルに対して同一のテーブルが渡されることもあります。
  • tableSize は各テーブルに含まれるエントリの数を示します。
  • テーブルは必要に応じて補間され、ハードウェアが必要とするサンプルの数を生成します。
CGDisplayErr CGGetDisplayTransferByTable(
    CGDirectDisplayID display,
    CGTableCount capacity,
    CGGammaValue  *redTable,
    CGGammaValue  *greenTable,
    CGGammaValue  *blueTable,
    CGTableCount *sampleCount);
  • ディスプレイ転送テーブルを取得します。
  • capacity は各配列が保持できるサンプルの数を示します。
  • sampleCount には、実際にコピーされたサンプルの数が書き込まれます。
CGSetDisplayTransferByByteTable(
    CGDirectDisplayID display,
    CGTableCount tableSize,
    const CGByteValue  *redTable,
    const CGByteValue  *greenTable,
    const CGByteValue  *blueTable);
  • 各チャネルに対応するバイト値のテーブルを使用して、ディスプレイガンマ/転送関数を設定します。
  • それぞれのテーブル内の値は、0 から 255 までの範囲の値を含んでいなければなりません。
  • 赤、緑、および青チャネルに対して同一のテーブルが渡されることもあります。
  • tableSize は各テーブルに含まれるエントリの数を示します。
  • テーブルは必要に応じて補間され、ハードウェアが必要とするサンプルの数を生成します。
boolean_t CGDisplayCanSetPalette(
    CGDirectDisplayID display);
  • 指定されたディスプレイがパレットをサポートしている場合に true を返します。
  • 8 ビット疑似カラーのみ。
CGDisplayErr CGDisplaySetPalette(
    CGDirectDisplayID display,
    const CGDirectPaletteRef palette);
  • 指定されたディスプレイ ID に対応するパレットを設定します。
  • なお、現在のガンマ関数は、それらがハードウェアにロードされる前にパレットの要素に適用されます。

ページの先頭に戻る

 

CoreGraphics シールドウインドウへのアクセス

void * CGShieldingWindowID(
    CGDirectDisplayID display);
  • 描画サーフェス API とともに使用するため、CoreGraphics ローシールドウインドウを返します。
  • ディスプレイ ID が無効な場合、またはディスプレイがシールドされていない場合に NULL を返します。
int32_t CGShieldingWindowLevel(void);
  • シールドウインドウに使用するウインドウレベルを返します。
  • この値は、シールドウインドウと同じウインドウレベルで Cocoa ウインドウを位置付けるために使用されることもあります。

ページの先頭に戻る

 

マウスカーソルの制御

CGDisplayErr CGDisplayHideCursor(
    CGDirectDisplayID display);
  • 非表示カーソルカウントを増加させ、必要に応じて、マウスカーソルを非表示にします。
CGDisplayErr CGDisplayShowCursor(
    CGDirectDisplayID display);
  • 非表示カーソルカウントを減少させ、必要に応じて、マウスカーソルを表示します。
CGDisplayErr CGDisplayMoveCursorToPoint(
    CGDirectDisplayID display, CGPoint point);
  • ディスプレイの原点 (ディスプレイの左上隅) を基準にして、マウスカーソルを指定された位置に移動します。
  • 正常終了時に kCGDisplayNoErr を返します。
  • なお、この移動の結果としてイベントが発生することはありません。
  • 指定された位置がデスクトップの外部にある場合は、デスクトップ内に収まるように切り詰められます。
void CGGetLastMouseDelta(
    CGMouseDelta * deltaX,
    CGMouseDelta * deltaY );
  • このアプリケーションによって最後に受信されたマウス移動イベントに関連付けられているマウス位置の変更を返します。

ページの先頭に戻る

 

垂直ブランクの待機

CGDisplayErr CGDisplayWaitForBeamPositionOutsideLines(
    CGDirectDisplayID display,
    CGBeamPosition upperScanLine,
    CGBeamPosition lowerScanLine );
  • ビーム位置が upperScanLine と lowerScanLine で指定された範囲の外部に出るまで待機します。
  • 正常終了時には kCGDisplayNoErr を返し、ディスプレイ、upperScanLine、または lowerScanLine が無効な場合にはエラーを返します。
  • なお、upperScanLine と lowerScanLine がディスプレイの高さ全体を囲む場合、この関数はエラーを返します。
  • lowerScanLine は upperScanLine 以上でなければなりません。
  • 一部のディスプレイシステムでは、ディスプレイをリフレッシュするときに一般的な垂直および水平掃引を使用しないことがあります。これらのディスプレイは、CGDisplayCurrentMode によって返される CFDictionaryRef の中に 0 という kCGDisplayRefreshRate をレポートし、このようなディスプレイでは、CGDisplayWaitForBeamPositionOutsideLines は一度だけ値を返します。
  • upperScanLine と lowerScanLine は、描画操作を完了するために十分なリードタイムを許可しなければなりません。ビームが描画領域の下端を通過するのを待ち、ほとんど完全な垂直掃引周期により描画を実行できるようにするというのがよく使用される戦略です。このためには、upperScanLine に 0 を設定し、次のように lowerScanLine に境界ボックスの下端を設定します。
    lowerScanLine = (CGBeamPosition)(cgrect.origin.y + cgrect.size.height);
CGBeamPosition CGDisplayBeamPosition(
    CGDirectDisplayID display );
  • ディスプレイ上での現在のビーム位置を返します。
  • ディスプレイが無効な場合、またはディスクプレイがペインティングを行うために一般的な垂直掃引を実装していない場合に 0 を返します。

     

ページの先頭に戻る

 

要約

このテクニカルノートでは、重要なデータ型、関数呼び出し、および典型的な使用パターンなど、CGDirectDisplay API の使用を始めるときに必要となる基本的な情報について説明しました。CGDirectPalette API の使い方については、「Technical Note 2008」を参照してください。